﻿using System;
using System.Text;
using System.IO;

namespace BpmConnection2Sec
{
    class Make3270CfgFile
    {
        private InfoUser _user = null;
        private bool _isScAuth = false;
        private static Logger logger = Logger.getInstance();
        //serve per la generazione del file ext .ws di produzione con accesso con SC
        private const string SMART_CARD_TEMPLATE = "[SCT]";
        //serve per la generazione del file ext .ws di produzione con accesso senza SC
        private const string NO_SMART_CARD_TEMPLATE = "[NSCT]";
        //serve per la generazione del file ext .ws di produzione per la sessione printer di produzione
        private const string PRT_PROD_TEMPLATE = "[PRTT]";
        //serve per la generazione del file ext .ws di sviluppo
        private const string DEV_TEMPLATE = "[DEVT]";
        //serve per la generazione del file ext .ws di sviluppo printer
        private const string DEV_PRT_TEMPLATE = "[DPRT]";

        public static String OutputWSFolderPath  = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
        public static String InputCFGFolderPath  = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);

        public static string CFG_3270_FILE_NAME_SC = OutputWSFolderPath + "\\3270SC.ws";
        public static string CFG_3270_FILE_NAME_SC_BACKUP = OutputWSFolderPath + "\\3270SC.bck";
        //Puoi commentarle tanto gestisci un unico file
        public static string CFG_3270_FILE_NAME_NO_SC = OutputWSFolderPath + "\\3270NOSC.ws";
        public static string CFG_3270_FILE_NAME_NO_SC_BACKUP = OutputWSFolderPath + "\\3270NOSC.bck";


        private static string cfg3270PrinterFileName = OutputWSFolderPath + "\\3270PrinterP.ws";
        private static string cfg3270DevelopFileName = OutputWSFolderPath + "\\3270SVI.ws";
        private static string cfg3270DevelopFileNameBackup = OutputWSFolderPath + "\\3270SVI.bck";
        private static string cfg3270PrinterDevelopFileName = OutputWSFolderPath + "\\3270PrinterSVI.ws";
        public static string LCK_3270_FILE_NAME = OutputWSFolderPath + "\\3270.lck";
        public static string CFG_3270_TEMPLATE = InputCFGFolderPath + "\\3270.cfg";//NB: il template è il .cfg del progetto

        /**
         * informazioni sul file:
         * [Telnet3270]
         * identifica la sezione che contiene le informaizoni di connessione del 3270.
         * Potrebbe avere senso l'unica inizializzazione: 
         * LUName=@VIDEO_LU_TERMINAL@
         * [Window]
         * UserTitle=@VIDEO_LU_TERMINAL@ (senza dollaro o lira) 
         * 
         **/
        public Make3270CfgFile(InfoUser user)
        {
            //NB: il template dovrà stare nella medesima directory dell'ufficiale
            //Devo passare un oggetto che contenga tutte le informazioni utili
            //Config3270File(_path+"/3270.cfg", _path + "/3270.ws");            
            this._user = user;
        }     

        public void config3270File()
        {
            _isScAuth = this._user.isUserAuthenticatedWithSmartCard();
            if (_isScAuth) logger.log("User authentication: SMARTCARD", "STD");
            else logger.log("User authentication: NO SMARTCARD", "STD");
            //Voglio gestire un unico file allora non faccio distinzione
            //this.config3270File(CFG_3270_TEMPLATE, (_isScAuth) ? CFG_3270_FILE_NAME_SC : CFG_3270_FILE_NAME_NO_SC, cfg3270PrinterFileName);
            this.config3270File(CFG_3270_TEMPLATE, CFG_3270_FILE_NAME_SC, cfg3270PrinterFileName, false);
        }     

        //TODO gestire le eccezioni
        public void update3270FileOrgUnitChanged() {
            //ricaricare il valore dei terminali, sia di quelli di produzione
            //che gli eventulai di sviluppo, che quelli printer.            
            string fileData = "";
            string prtFileData = "";
            //+ file da caricare e modificare --> da capire come
           
            using (StreamReader sr = new StreamReader(CFG_3270_FILE_NAME_SC))
            {
                fileData = sr.ReadToEnd();
            }
            using (StreamReader pr = new StreamReader(cfg3270PrinterFileName))
            {
                prtFileData = pr.ReadToEnd();
            }

            StringBuilder produzione = new StringBuilder(fileData);
            StringBuilder newTerm = new StringBuilder("LUName=").Append(this._user.getVideoTerminalCode()).Append('\r');            
            string oldTerm = fileData.Substring(fileData.IndexOf("LUName=")).Split(new string[] { "\u000D" }, StringSplitOptions.None)[0];
            logger.log("Sostituzione del vecchio terminale video >>>" + oldTerm, "STD");                        
            produzione.Replace(oldTerm, newTerm.ToString());
            flush3270CfgFile(CFG_3270_FILE_NAME_SC, produzione.ToString());
            logger.log("<<< con il nuovo:" + newTerm, "STD");                        
            //la printer...
            StringBuilder produzionePrt = new StringBuilder(prtFileData);
            StringBuilder newPrtTerm = new StringBuilder("LUName=").Append(this._user.getPrinterTerminalCode()).Append('\r');
            string oldPrtTerm = prtFileData.Substring(prtFileData.IndexOf("LUName=")).Split(new string[] { "\u000D" }, StringSplitOptions.None)[0];
            logger.log("Sostituzione del vecchio terminale printer >>>" + oldPrtTerm, "STD"); 
            produzionePrt.Replace(oldPrtTerm, newPrtTerm.ToString());
            flush3270CfgFile(cfg3270PrinterFileName, produzionePrt.ToString());
            logger.log("<<< con il nuovo:" + newPrtTerm, "STD");     
            if (this._user.hasDevelopEnvironment())
            {
                //anche lo sviluppo: se l'utente arriva da un non sviluppo bisonga ricrearli da zero; quindi se si entra in questo if
                //l'utente non ha il file di sviluppo catturo l'eccezione e li ricreo.
                string sviFileData = "";
                string sviPrtFileData = "";
                //sistemare i controlli

                if (File.Exists(cfg3270DevelopFileName))
                {
                    //eseguo l'update
                    using (StreamReader sr = new StreamReader(cfg3270DevelopFileName))
                    {
                        sviFileData = sr.ReadToEnd();
                    }
                    using (StreamReader pr = new StreamReader(cfg3270PrinterDevelopFileName))
                    {
                        sviPrtFileData = pr.ReadToEnd();
                    }
                    StringBuilder sviluppo = new StringBuilder(sviFileData);
                    StringBuilder newSviTerm = new StringBuilder("LUName=").Append(this._user.getVideoTerminalCodeForDevelopEnvironment()).Append('\r');
                    string oldSviTerm = sviFileData.Substring(sviFileData.IndexOf("LUName=")).Split(new string[] { "\u000D" }, StringSplitOptions.None)[0];
                    logger.log("Sostituzione del vecchio terminale video di sviluppo>>>" + oldSviTerm, "STD");
                    produzione.Replace(oldSviTerm, newSviTerm.ToString());
                    flush3270CfgFile(cfg3270DevelopFileName, sviluppo.ToString());
                    logger.log("<<< con il nuovo:" + newSviTerm, "STD");
                    //la printer...
                    StringBuilder sviluppoPrt = new StringBuilder(sviPrtFileData);
                    StringBuilder newSviPrtTerm = new StringBuilder("LUName=").Append(this._user.getPrinterTerminalCodeForDevelopEnvironment()).Append('\r');
                    string oldSviPrtTerm = sviPrtFileData.Substring(sviPrtFileData.IndexOf("LUName=")).Split(new string[] { "\u000D" }, StringSplitOptions.None)[0];
                    logger.log("Sostituzione del vecchio terminale printer di sviluppo>>>" + oldSviPrtTerm, "STD");
                    produzionePrt.Replace(oldSviPrtTerm, newSviPrtTerm.ToString());
                    flush3270CfgFile(cfg3270PrinterDevelopFileName, sviluppoPrt.ToString());
                    logger.log("<<< con il nuovo:" + newSviPrtTerm, "STD");
                }
                else { 
                    //passato da un no dev a un dev, va ricreato da zero.
                    this.config3270File(CFG_3270_TEMPLATE, CFG_3270_FILE_NAME_SC, cfg3270PrinterFileName, true);
                }               
            }
        }

        public void update3270FileSmartCardLogon(){
            
            string fileData = "";
            using (StreamReader sr = new StreamReader(CFG_3270_FILE_NAME_SC))
            {
                fileData = sr.ReadToEnd();                
            }
            StringBuilder produzione = new StringBuilder(fileData);
            if (this._user.isUserAuthenticatedWithSmartCard())
            {
                produzione.Replace("HostPortNumber=23", "HostPortNumber=20023");
                produzione.Replace("Security=N", "Security=Y");
                produzione.Replace("#OpenMacro=logon.MAC", "OpenMacro=logon.MAC");
            }
            else
            {
                produzione.Replace("HostPortNumber=20023", "HostPortNumber=23");
                produzione.Replace("Security=Y", "Security=N");
                produzione.Replace("OpenMacro=logon.MAC", "#OpenMacro=logon.MAC");
            }
            flush3270CfgFile(CFG_3270_FILE_NAME_SC, produzione.ToString());
        }

        private void config3270File(string fileNameCfgTemplate, string fileNameCfgDestination, string fileNamePrtCfgDestination, Boolean needNewDevFiles)
        {
            StringBuilder produzione = new StringBuilder();
            StringBuilder produzionePrinter = new StringBuilder();
            StringBuilder developRecords = new StringBuilder();
            StringBuilder developPrinterRecords = new StringBuilder();
            bool hasDevEnv = this._user.hasDevelopEnvironment();
            try
            {
                string fileData = "";
                using (StreamReader sr = new StreamReader(fileNameCfgTemplate))
                {
                    fileData = sr.ReadToEnd().Replace("\r", "");
                }

                string[] records = fileData.Split("\n".ToCharArray());

                //devo dividere i template
                foreach (string record in records)
                {
                    //Per il DEVEL non è mai con SC
                    //Voglio gestire un unico file, allora uso quello generico commentando le righe solo nel caso NSC
                    if (record.StartsWith(SMART_CARD_TEMPLATE))
                        produzione.Append(record.Replace(SMART_CARD_TEMPLATE, "")).Append("\r");

                    //Nel caso di auth senza SC non serve la sezione security e OpenMacro
                    if (!_isScAuth)
                    {
                        //Imposto security a N e commento OpenMacro
                        produzione.Replace("Security=Y", "Security=N");
                        produzione.Replace("OpenMacro=logon.MAC", "#OpenMacro=logon.MAC");
                    }
                    

                    if (record.StartsWith(PRT_PROD_TEMPLATE))
                    {
                        produzionePrinter.Append(record.Replace(PRT_PROD_TEMPLATE, "")).Append("\r");
                    }

                    if (hasDevEnv)
                    {
                        if (record.StartsWith(DEV_PRT_TEMPLATE))
                        {
                            developPrinterRecords.Append(record.Replace(DEV_PRT_TEMPLATE, "")).Append("\r");
                        }
                        if (record.StartsWith(DEV_TEMPLATE))
                        {
                            developRecords.Append(record.Replace(DEV_TEMPLATE, "")).Append("\r");
                        }
                    }

                }
                produzione.Replace("@PORT_NUMBER@", _isScAuth ? "20023" : "23");
                produzione.Replace("@VIDEO_LU_TERMINAL@", this._user.getVideoTerminalCode());
                string pathcfg = System.Environment.GetEnvironmentVariable("BPM3270USER");
                if (pathcfg!=null){
                    produzione.Replace("@BPM3270USER@", pathcfg);
                    if (hasDevEnv) developRecords.Replace("@BPM3270USER@", pathcfg);
                }                
                if (hasDevEnv) developRecords.Replace("@DEV_VIDEO_LU_TERMINAL@", this._user.getVideoTerminalCodeForDevelopEnvironment());
                produzionePrinter.Replace("@PRINTER_LU_TERMINAL@", this._user.getPrinterTerminalCode());
                if (hasDevEnv) developPrinterRecords.Replace("@DEV_PRINTER_LU_TERMINAL@", this._user.getPrinterTerminalCodeForDevelopEnvironment());

            }
            catch (FileNotFoundException fne)
            {
                Console.WriteLine(fne.Message);
                logger.log("ERROR with Template file: " + fne.Message, "ERR");
                Environment.ExitCode = 1;
                //System.Windows.Forms.MessageBox.Show("ERROR with Template file. " + fne.Message, "APPLICATION ERROR", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                throw new Exception("ERROR with Template file. " + fne.Message);
            }

            //Scrivo le stringhe costruite nei file
            if (!needNewDevFiles) flush3270CfgFile(fileNameCfgDestination, produzione.ToString());
            if (!needNewDevFiles) flush3270CfgFile(fileNamePrtCfgDestination, produzionePrinter.ToString());
            if (hasDevEnv) flush3270CfgFile(cfg3270DevelopFileName, developRecords.ToString());
            if (hasDevEnv) flush3270CfgFile(cfg3270PrinterDevelopFileName, developPrinterRecords.ToString());
        }

        private void flush3270CfgFile(string cfg3270FileName, string fileModified)
        {
            try
            {
                using (FileStream fs = new FileStream(cfg3270FileName, FileMode.Create, FileAccess.Write, FileShare.None))
                using (StreamWriter w = new StreamWriter(fs))
                {
                    w.Write(fileModified);
                    w.Close();
                }
                logger.log("File " + cfg3270FileName + " created succesfully!", "STD");
            }catch(Exception ex){
                Console.WriteLine("ERROR while creating configuration files: "+ex.Message);
                logger.log("ERROR while creating configuration files: " + ex.Message, "ERR");
                Environment.ExitCode = 1;
                //System.Windows.Forms.MessageBox.Show("ERROR while creating configuration files. " + ex.Message, "APPLICATION ERROR", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                throw new Exception("ERROR while creating configuration files. " + ex.Message);
            }
        }

        public static void updateWSFilesPath(String path)
        {
            CFG_3270_FILE_NAME_SC = path + "\\3270.ws";
            CFG_3270_FILE_NAME_SC_BACKUP = path + "\\3270SC.bck";
            cfg3270PrinterFileName = path + "\\3270PrinterP.ws";
            cfg3270DevelopFileName = path + "\\3270SVI.ws";
            cfg3270DevelopFileNameBackup = path + "\\3270SVI.bck";
            cfg3270PrinterDevelopFileName = path + "\\3270PrinterSVI.ws";
            LCK_3270_FILE_NAME = path + "\\3270.lck";
        }

        public static void updateCFGFilesPath(String path)
        {
            CFG_3270_TEMPLATE = path + "\\3270.cfg";
        }

        
    }
}
